package dhadi.use.swing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dhadi.model.Board;
import dhadi.model.Edge;
import dhadi.model.Node;

public class Layout
{
	static final Color PLAYER_A_COLOR = Color.GREEN;
	private static final Color PLAYER_B_COLOR = Color.BLUE;
	private static final Color MESSAGE_COLOR = Color.WHITE;
	
	private PlayerUi playerA;
	private PlayerUi playerB;
	private PlayerUi curretPlayer;
	
	private Map<Node,NodeUi> nodes = new HashMap<Node,NodeUi>();
	private Map<Edge,EdgeUi> edges = new HashMap<Edge,EdgeUi>();
	private Board board = null;
	private BoardUi boardUi = null;
	private int startX = 0;
	private int startY = 0;
	
	private Point messagePosition;
	
	
	public Layout(Board board, BoardUi boardUi) {
		this.board = board;
		this.boardUi = boardUi;
		this.playerA = new PlayerUi(
				this.boardUi.board.getPlayerA(),
				this.boardUi,Layout.PLAYER_A_COLOR);
		
		this.playerB = new PlayerUi(
				this.boardUi.board.getPlayerB(),
				this.boardUi,Layout.PLAYER_B_COLOR);
		
		this.playerA.setOpponent(this.playerB);
		this.playerB.setOpponent(this.playerA);		
	}
	
	public PickUi getMatchingPic(int x, int y)
	{
		PlayerUi player = this.currentPlayer();
		if (player == null) {
			return null;
		}
		
		if (!this.boardUi.isOwner(player.getPlayer())) return null;
		    
		
		// If current player made a dhadi, 
		// allow him to pick opponent picks on board
		if (player.getPlayer().isDhadiByYou()) {
			return getMatchingPic(
					player.getPicksToKill(),x,y);		
		} else {
			return getMatchingPic(player.getPicksToMove(),x,y);
		}
	}
	
	private PlayerUi currentPlayer() {
		return this.curretPlayer;
	}

	private PickUi getMatchingPic(List<PickUi> picks, int x, int y)
	{
		for (PickUi pick : picks)
		{
			if (pick != null && pick.isInRegion(x, y))
				return pick;
		}
		return null;
	}
	
	public void drawLayout(Graphics g)
	{
		int innerSpace = g.getClip().getBounds().width/10;
		int x = (g.getClip().getBounds().width/2)-innerSpace*3;
		int y = (g.getClip().getBounds().height/2)-innerSpace*3;
		
		// Adjustment to fit player picks at the bottom
		y = y - 90;
		
		if (this.startX != x ||
		    this.startY != y)
		{
			int w = (innerSpace)*6;
			int h = (innerSpace)*6;
			this.calculateNodePositions(x,y,w,h,innerSpace);
			this.calculateEdgePositions();
			
			this.playerA.setPosition(new Point(x, y+h+40));
			this.playerB.setPosition(new Point(x, this.playerA.getPosition().y+60));
			
			this.startX = x;
			this.startY = y;
			this.messagePosition = new Point(x, this.playerB.getPosition().y+50);
		}
		
		g.setColor(Color.BLACK);
		this.drawEdges(g);
		
		g.setColor(Color.BLACK);
		this.drawNodes(g);
		
		g.setColor(Color.BLACK);
		this.drawNodeLetters(g);
		
		this.playerA.draw(g);
		this.playerB.draw(g);
		
		/*this.drawPicks(g,this.playerA.getPicks());
		this.drawPicks(g,this.playerB.getPicks());
		
		g.setColor(Layout.PLAYER_A_COLOR);
		this.drawText(g,"Player A:",this.playerA.getPosition());
		g.setColor(Layout.PLAYER_B_COLOR);
		this.drawText(g,"Player B:",this.playerB.getPosition());*/
		
		g.setColor(Layout.MESSAGE_COLOR);
		this.drawMessage(g);
	}

	private void drawMessage(Graphics g) {
		if (this.boardUi.notificationMessage != null) {
			this.drawText(g, this.boardUi.notificationMessage, this.messagePosition);
		}
	}

	private void drawText(Graphics g, String string, Point playerPosition) {
		byte[] bytes = string.getBytes();
		g.drawBytes(bytes, 0, bytes.length, playerPosition.x, playerPosition.y);
	}
	
	private void drawNodes(Graphics g) {
		NodeUi n = null;
		for (Node node : this.board.getNodes())
		{
			n = this.getNodeUi(node);
			n.draw(g);			
		}
	}
	
	private void drawNodeLetters(Graphics g) {
		NodeUi n = null;
		for (Node node : this.board.getNodes())
		{
			n = this.getNodeUi(node);
			byte[] bytes = node.name.getBytes();
			g.drawBytes(bytes, 0, bytes.length, n.getLocation().x-3, n.getLocation().y+5);
		}
	}

	private void drawEdges(Graphics g) {
		
		Color oldColor = g.getColor();
		g.setColor(Color.LIGHT_GRAY);
		EdgeUi e = null;
		for (Edge edge : this.board.getEdges())
		{
			e = this.getEdge(edge);
			if (e != null)
				e.draw(g);			
		}
		g.setColor(oldColor);
	}

	private void calculateNodePositions(int x, int y, int w, int h, int innerSpace)
	{
		int midX = 0;
		int midY = 0;
		
		this.addNodePoint("A",x,y);
		this.addNodePoint("C",x+w, y);
		this.addNodePoint("V",x, y+h);
		this.addNodePoint("X",x+w, y+h);
		
		midX = x + w/2;
		midY = y + h/2;	
		
		this.addNodePoint("B",midX, y);
		this.addNodePoint("J",x, midY);
		this.addNodePoint("O",x+w, midY);
		this.addNodePoint("W",midX, y+h);
		
		
		x += innerSpace;
		y += innerSpace;
		w -= innerSpace*2;
		h -= innerSpace*2;
		
		this.addNodePoint("D",x,y);
		this.addNodePoint("F",x+w, y);
		this.addNodePoint("S",x, y+h);
		this.addNodePoint("U",x+w, y+h);
		
		midX = x + w/2;
		midY = y + h/2;	
		
		this.addNodePoint("E",midX, y);
		this.addNodePoint("K",x, midY);
		this.addNodePoint("N",x+w, midY);
		this.addNodePoint("T",midX, y+h);
		
		
		x += innerSpace;
		y += innerSpace;
		w -= innerSpace*2;
		h -= innerSpace*2;
		
		this.addNodePoint("G",x,y);
		this.addNodePoint("I",x+w, y);
		this.addNodePoint("P",x, y+h);
		this.addNodePoint("R",x+w, y+h);
		midX = x + w/2;
		midY = y + h/2;
		
		this.addNodePoint("H",midX, y);
		this.addNodePoint("L",x, midY);
		this.addNodePoint("M",x+w, midY);
		this.addNodePoint("Q",midX, y+h);
	 }
	
	private void calculateEdgePositions()
	{
		for (Edge edge : this.board.getEdges())
		{
			this.addEdge(edge, 
						 this.getNodeUi(edge.getNodeA()), 
						 this.getNodeUi(edge.getNodeB()));
		}
	}
	
	public Map<Node, NodeUi> getNodes() {
		return this.nodes;
	}
	
	public List<NodeUi> getEmptyNodes() {
		Collection<NodeUi> nodes = this.getNodes().values();
		List<NodeUi> emptyNodes = new ArrayList<NodeUi>(nodes.size());
		for (NodeUi n : nodes)
		{
			if (n.node.isNodeEmpty())
				emptyNodes.add(n);
		}
		return emptyNodes;
	}

	private void addNodePoint(String nodeName, int x, int y) {
		Node node = this.board.findNodeByName(nodeName);
		NodeUi nodeUi = this.nodes.get(node);
		if (nodeUi == null)
		{
			nodeUi = new NodeUi(x,y, node,this);
			this.nodes.put(node, nodeUi);
		}
		else
		{
			nodeUi.setLocation(x, y);
		}	
	}
	
	public NodeUi getNodeUi(Node node) {
		return this.nodes.get(node);
	}
	
	private void addEdge(Edge edge, NodeUi a, NodeUi b)
	{
		this.edges.put(edge, new EdgeUi(a,b));
	}
	
	private EdgeUi getEdge(Edge edge)
	{
		return this.edges.get(edge);
	}

	public List<NodeUi> convertToUi(List<Node> nodes) {
		List<NodeUi> uiNodes = new ArrayList<NodeUi>();
		for(Node n : nodes)
		{
			uiNodes.add(this.nodes.get(n));						
		}
		return uiNodes;
	}

	public void applyModelChanges() {
		
		if (this.board.currentPlayer().equals(this.playerA.getPlayer())) {
			this.curretPlayer = this.playerA;
		} else if (this.board.currentPlayer().equals(this.playerB.getPlayer())) {
			this.curretPlayer = this.playerB;
		}
		
		this.playerA.applyModelChanges();
		this.playerB.applyModelChanges();
	}
}